﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using AppToolkit.WPF.Services;
using AppToolkit.WPF.UI;
using Moq;
using NUnit.Framework;
using log4net;

namespace AppToolkit.WPF.Tests.Services
{
    [TestFixture]
    public class ErrorDisplayServiceTests
    {
        private Mock<ILog> _logMock;
        private Mock<IErrorReportDialog> _dialogMock;

        [SetUp]
        public void Setup()
        {
            _logMock = new Moq.Mock<ILog>();
            _dialogMock = new Moq.Mock<IErrorReportDialog>();
        }

        [TearDown]
        public void Dispose()
        {
            UnitTestUtils.UI.UITestHelper.CleanupDispatcher();
        }

        #region Owner Property Tests
        [Test]
        public void OwnerIsSetCorrectly()
        {
            var target = new ErrorDisplayService(_logMock.Object, _dialogMock.Object);

            _dialogMock.SetupSet(m => m.Owner = null);

            Assert.Throws<ArgumentException>(() => target.ShowException(new ArgumentException("Test")));
        }

        [Test, STAThread]
        public void OwnerIsSetCorrectlyToMainWindow()
        {
            var mainWindow = new Window();

            _dialogMock.SetupSet(m => m.Owner = mainWindow);

            var target = new ErrorDisplayService(_logMock.Object, _dialogMock.Object);

            target.MainWindow = mainWindow;

            Assert.Throws<ArgumentException>(() => target.ShowException(new ArgumentException("Test")));
        }

        [Test, STAThread]
        public void OwnerIsSetCorrectlyToOwner()
        {
            var window = new Window();

            var target = new ErrorDisplayService(_logMock.Object, _dialogMock.Object);
            
            _dialogMock.SetupSet(m => m.Owner = window);

            // set MainWindow so that it would throw
            target.MainWindow = new Window();

            Assert.Throws<ArgumentException>(() => target.ShowException(new ArgumentException("Test"), window));
        }
        #endregion

        [Test]
        public void ExceptionsAreLoggedAsFatal()
        {
            var target = new ErrorDisplayService(_logMock.Object, _dialogMock.Object);

            Assert.Throws<ArgumentException>(() => target.ShowException(new ArgumentException("Test")));

            _logMock.Verify(m => m.Fatal(It.Is<string>(s => s.Contains("Unhandled exception caught which requires shutting down")), It.Is<Exception>(e => e is ArgumentException)));
        }

        [Test]
        public void ExceptionCanBeIgnoredByUser()
        {
            var target = new ErrorDisplayService(_logMock.Object, _dialogMock.Object);

            // should be logged as Error
            _dialogMock.Setup(m => m.IgnoreError).Returns(true);

            target.ShowException(new ArgumentException("Test"));

            _logMock.Verify(m => m.Warn(It.Is<string>(s => s.Contains("Unhandled exception was ignored by user")), It.Is<ArgumentException>(e => e is ArgumentException)));
        }
    }

    [TestFixture]
    public class ErrorDisplayService_UI_Tests
    {
        private Mock<ILog> _logMock;
        private Mock<IErrorReportDialog> _dialogMock;

        [SetUp]
        public void Setup()
        {
            _logMock = new Moq.Mock<ILog>();
            _dialogMock = new Moq.Mock<IErrorReportDialog>();
        }

        [TearDown]
        public void Dispose()
        {
            UnitTestUtils.UI.UITestHelper.CleanupDispatcher();
        }

        [Test, STAThread, Explicit]
        public void DesiredResult()
        {
            var window = new Window();

            ErrorDisplayService errorDisplayService = null;

            window.Loaded += (sender, args) =>
                                 {
                                      errorDisplayService= new ErrorDisplayService(_logMock.Object, _dialogMock.Object);
                                 };
            window.ShowDialog();
        }
    }
}
